#include "headers.h"

bool Grammar::ReadFromXML(QDomElement root)
{
    if(root.isNull())
    {
        QMessageBox::information(NULL, QObject::tr("JCmp"),
                                 QObject::tr("The file doesn't contains grammar description"));
        return false;
    }
    if(root.tagName()!="grammar")
    {
        QMessageBox::information(NULL, QObject::tr("JCmp"),
                                 QObject::tr("Wrong grammar node"));
        return false;
    }
    QDomElement child=root.firstChildElement("nonterminals");
    if(child.isNull())
    {
        QMessageBox::information(NULL, QObject::tr("JCmp"),
                                 QObject::tr("The file doesn't contains nonterminals description"));
        return false;
    }
    nonterminals=child.text().split(QRegExp("\\s+"), QString::SkipEmptyParts).toSet();
    if(nonterminals.isEmpty())
    {
        QMessageBox::information(NULL, QObject::tr("JCmp"),
                                 QObject::tr("Empty list of nonterminals"));
        return false;
    }
    child=root.firstChildElement("terminals");
    if(child.isNull())
    {
        QMessageBox::information(NULL, QObject::tr("JCmp"),
                                 QObject::tr("The file doesn't contains terminals description"));
        return false;
    }
    terminals=child.text().split(QRegExp("\\s+"), QString::SkipEmptyParts).toSet();
    foreach(QString str, nonterminals)
    {
        if(str=="START")
        {
            QMessageBox::information(NULL, QObject::tr("JCmp"),
                                     QObject::tr("Term \"START\" is forbiden to use in current version of Parser Generator. Contact your dealer").arg(str));
            return false;

        }
    }
    if(terminals.isEmpty())
    {
        QMessageBox::information(NULL, QObject::tr("JCmp"),
                                 QObject::tr("Empty list of terminals"));
        return false;
    }
    foreach(QString str, terminals)
    {
        if(nonterminals.contains(str))
        {
            QMessageBox::information(NULL, QObject::tr("JCmp"),
                                     QObject::tr("Term \"%1\" duplicates in terminals and nonterminals lists").arg(str));
            return false;
        }
        if(str=="START")
        {
            {
                QMessageBox::information(NULL, QObject::tr("JCmp"),
                                         QObject::tr("Term \"START\" is forbiden to use in current version of Parser Generator. Contact your dealer").arg(str));
                return false;
            }
        }
    }
    child=root.firstChildElement("rules");
    if(child.isNull())
    {
        QMessageBox::information(NULL, QObject::tr("JCmp"),
                                 QObject::tr("The file doesn't contains rules description"));
        return false;
    }
    rules.clear();
    QStringList rulesSet=child.text().split("\n", QString::SkipEmptyParts);
    foreach(QString line, rulesSet)
    {
        if(line.trimmed().isEmpty())
            continue;
        QStringList rule = line.split(QRegExp("(->)|(=::)"));
        if(rule.length()!=2)
        {
            QMessageBox::information(NULL, QObject::tr("JCmp"),
                                     QObject::tr("Cant determine left hand side and right hand side in rule \"%1\"").arg(line.trimmed()));
            return false;
        }
        QString lhs = rule.first().trimmed();
        if(!nonterminals.contains(lhs))
        {
            QMessageBox::information(NULL, QObject::tr("JCmp"),
                                     QObject::tr("Unknown left hand side of rule \"%1\". Left hand side must be presented in nonterminals list").arg(line.trimmed()));
            return false;
        }
        QStringList rhs = rule.last().split(QRegExp("\\s+"), QString::SkipEmptyParts);
        foreach(QString str, rhs)
        {
            if(!nonterminals.contains(str) && !terminals.contains(str))
            {
                QMessageBox::information(NULL, QObject::tr("JCmp"),
                                         QObject::tr("Unknown right hand side of rule \"%1\". Unknown term \"%2\"").arg(line.trimmed()).arg(str));
                return false;
            }
        }
        rules.append(Rule(lhs, rhs));
    }
    if(rules.isEmpty())
    {
        QMessageBox::information(NULL, QObject::tr("JCmp"),
                                 QObject::tr("Empty list of rules"));
        return false;
    }
    child=root.firstChildElement("first_symbol");
    if(child.isNull())
    {
        QMessageBox::information(NULL, QObject::tr("JCmp"),
                                 QObject::tr("The file doesn't contains first symbol description"));
        return false;
    }
    QString fS=child.text().trimmed();
    if(!nonterminals.contains(fS))
    {
        QMessageBox::information(NULL, QObject::tr("JCmp"),
                                 QObject::tr("Unknown first symbol \"%1\". First symbol must be presented in nonterminals list").arg(fS));
        return false;
    }
    firstSymbol=fS;
    return true;
}

bool Grammar::ReadFromXML(QString fileName)
{
    QString errorMsg;
    int errorLine;
    int errorColumn;

    QFile file(fileName);
    if(!file.open(QIODevice::ReadOnly|QIODevice::Text))
    {
        QMessageBox::information(NULL, QObject::tr("JCmp"),
                                 QObject::tr("Error while opening file: %1")
                                 .arg(file.errorString()));
        return false;
    }
    QDomDocument domDoc;
    if(!domDoc.setContent(&file, true, &errorMsg, &errorLine, &errorColumn))
    {
        QMessageBox::information(NULL, QObject::tr("JCmp"),
                                 QObject::tr("Parse error at line %1, column %2:\n%3")
                                 .arg(errorLine)
                                 .arg(errorColumn)
                                 .arg(errorMsg));
        return false;
    }
    QDomElement root=domDoc.documentElement();
    return ReadFromXML(root);
}

bool Grammar::isEmpty()
{
    if(nonterminals.isEmpty() || terminals.isEmpty() || rules.isEmpty() || firstSymbol.isEmpty())
        return true;
    return false;
}

/** methods for output **/
QStringList Grammar::getNonterminals()
{
    return nonterminals.toList();
}
QStringList Grammar::getTerminals()
{
    return terminals.toList();
}
QStringList Grammar::getRules()
{
    QStringList list;
    foreach(Rule rule, rules)
        list.append(rule.toString());
    return list;
}
QString Grammar::getFirstSymbol()
{
    return firstSymbol;
}
/** ****************** **/
